import { HttpException, Injectable } from '@nestjs/common';
import { CreateOutboundplanDto } from 'src/dto/create-outboundplan.dto';
import { UpdateOutboundplanDto } from 'src/dto/update-outboundplan.dto';
import { Outboundplan } from 'src/entity/outboundplan.entity';
import { QueryOutboundplanDto } from 'src/dto/query-outboundplan.dto';
import { parseQueryParams } from 'src/common/utils';
import { Warehouse } from 'src/entity/warehouse.entity';
import { Box } from 'src/entity/box.entity';
import * as dayjs from 'dayjs';
import { Mercadosku } from 'src/entity/mercadosku.entity';
import { QueryWarehouseProductSkuDto } from 'src/dto/query-getProductAndSku.dto';

import * as ExcelJS from 'exceljs';
import * as path from 'path';
import { groupBoxesByWarehouseId } from 'src/common/utils/groupBy';

@Injectable()
export class OutboundplanService {
  async createMix(createOutboundplanDto: CreateOutboundplanDto, uid: any) {
    // data 是一个数组，数组里面是对象，对象里面是数组，数组里面是对象
    let data = JSON.parse(createOutboundplanDto.data);

    let boxList = [];

    for await (let sku of data) {
      // let boxs = await
      for await (let item of sku.boxNumberCountArray) {
        let queryRunner = Box.createQueryBuilder('box');
        queryRunner.leftJoinAndSelect('box.warehouse', 'warehouse');
        queryRunner.leftJoinAndSelect('box.mercadosku', 'mercadosku');

        queryRunner.andWhere('box.boxNumber = :boxNumber', {
          boxNumber: item.boxNumber,
        });

        queryRunner.andWhere('box.mercadoskuId = :mercadoskuId', {
          mercadoskuId: sku.skuId,
        });

        queryRunner.andWhere('box.status = :status', {
          status: 1,
        });

        queryRunner.orderBy('box.createTime', 'ASC');
        queryRunner.skip(0);
        queryRunner.take(item.num);

        let boxs = await queryRunner.getMany();

        boxList.push(...boxs);
      }
    }

    let groupBoxList = groupBoxesByWarehouseId(boxList);

    for await (let item of groupBoxList) {
      let skuList = [];

      item.belongBoxList.map((box: any) => {
        if (skuList.length == 0) {
          skuList.push({
            skuId: box.mercadosku.id,
            boxNumberCountArray: [
              {
                boxNumber: box.boxNumber,
                num: 1,
              },
            ],
            mercadoBoxNumber: '',
          });

          return;
        } else {
          let findSku = skuList.find((sku: any) => {
            let findBoxNumberCount = sku.boxNumberCountArray.find(
              (boxNumberCount) => {
                return boxNumberCount.boxNumber == box.boxNumber;
              },
            );

            return sku.skuId == box.mercadosku.id && findBoxNumberCount;
          });

          if (findSku == undefined) {
            skuList.push({
              skuId: box.mercadosku.id,
              boxNumberCountArray: [
                {
                  boxNumber: box.boxNumber,
                  num: 1,
                },
              ],
              mercadoBoxNumber: '',
            });
          } else {
            let findBoxNumberCount = findSku.boxNumberCountArray.find(
              (boxNumberCount) => {
                return boxNumberCount.boxNumber == box.boxNumber;
              },
            );
            console.log('findSku', findSku);
            console.log('findBoxNumberCount', findBoxNumberCount);

            if (findBoxNumberCount == undefined) {
              skuList.push({
                skuId: box.mercadosku.id,
                boxNumberCountArray: [
                  {
                    boxNumber: box.boxNumber,
                    num: 1,
                  },
                ],
                mercadoBoxNumber: '',
              });
            } else {
              findBoxNumberCount.num = findBoxNumberCount.num + 1;
            }
          }
        }
      });

      // 总箱数
      let totalBoxNumber = 0;
      // 总件数
      let stock = 0;

      skuList.map((item: any) => {
        item.boxNumberCountArray.map((item1: any) => {
          stock += Number(item1.boxNumber) * Number(item1.num);
          totalBoxNumber += Number(item1.num);
        });
      });

      let outboundplan = Outboundplan.create({
        warehouse: item,
        data: JSON.stringify(skuList),
        status: 1,
        adminId: uid,
      });

      outboundplan.totalNumber = stock;
      outboundplan.totalBoxNumber = totalBoxNumber;

      await outboundplan.save();

      for await (const box of boxList) {
        // 修改box的状态为已加入出库计划
        box.status = 2;

        if (box.warehouse.id == outboundplan.warehouse.id) {
          box.outboundplan = outboundplan;
        }

        box.mercadoBoxNumber = '';
        await box.save();
      }
    }

    return { boxList };
  }

  async create(createOutboundplanDto: CreateOutboundplanDto, uid: number) {
    let warehouse = await Warehouse.findOne({
      where: { id: createOutboundplanDto.warehouseId },
    });

    delete createOutboundplanDto.warehouseId;

    let outboundplan = Outboundplan.create({
      ...createOutboundplanDto,
      status: 1,
    });

    // 计算库存数量
    let data = JSON.parse(outboundplan.data);
    let stock = 0;
    let totalBoxNumber = 0;

    data.map((item: any) => {
      item.boxNumberCountArray.map((item1: any) => {
        stock += Number(item1.boxNumber) * Number(item1.num);
        totalBoxNumber += Number(item1.num);
      });
    });

    outboundplan.totalNumber = stock;
    outboundplan.totalBoxNumber = totalBoxNumber;
    outboundplan.warehouse = warehouse;
    outboundplan.adminId = uid;

    await outboundplan.save();

    let boxArray = [];

    for await (const item of data) {
      for await (const boxNumberCount of item.boxNumberCountArray) {
        let queryRunner = Box.createQueryBuilder('box');

        queryRunner.leftJoinAndSelect('box.mercadosku', 'mercadosku');
        queryRunner.leftJoinAndSelect('box.mercadoproduct', 'mercadoproduct');

        queryRunner.where('box.warehouseId = :warehouseId', {
          warehouseId: warehouse.id,
        });

        queryRunner.andWhere('box.mercadoskuId = :mercadoskuId', {
          mercadoskuId: item.skuId,
        });

        queryRunner.andWhere('box.boxNumber = :boxNumber', {
          boxNumber: boxNumberCount.boxNumber,
        });

        // 只查询在海外仓的箱子，已出库和已创建计划的不查
        queryRunner.andWhere('box.status = :status', {
          status: 1,
        });

        queryRunner.skip(0);
        queryRunner.take(boxNumberCount.num);

        let boxs = await queryRunner.getMany();

        boxArray = [...boxArray, ...boxs];
      }
    }

    for await (const box of boxArray) {
      // 修改box的状态为已加入出库计划
      box.status = 2;
      box.outboundplan = outboundplan;
      await box.save();
    }
  }

  async createDeShengExcel(id: number) {
    let outboundplan = await Outboundplan.findOneBy({ id });
    // 创建德胜出货Excel
    let workbook = new ExcelJS.Workbook();

    let queryRunner = Box.createQueryBuilder('box');

    queryRunner.leftJoinAndSelect('box.warehouse', 'warehouse');
    queryRunner.leftJoinAndSelect('box.mercadosku', 'mercadosku');
    queryRunner.leftJoinAndSelect('box.mercadoproduct', 'mercadoproduct');

    queryRunner.andWhere('box.outboundplanId = :outboundplanId', {
      outboundplanId: outboundplan.id,
    });

    queryRunner.orderBy('box.id', 'ASC');

    let boxs = await queryRunner.getMany();

    let worksheet = workbook.addWorksheet('Sheet 1');

    // 设置表头
    worksheet.columns = [
      { header: '箱号', key: 'name', width: 20 },
      { header: '产品图片', key: 'mercadoskuImage', width: 30 },
      { header: '产品型号', key: 'mercadoskuNumber', width: 10 },
      { header: '产品中文品名', key: 'mercadoproductName', width: 10 },
      { header: '产品英文品名', key: 'mercadoproductEnName', width: 10 },
      { header: '产品申报数量', key: 'boxNumber', width: 10 },
      { header: '产品申报单价', key: 'mercadoskuSalePrice', width: 10 },
      { header: '货箱重量(KG)', key: 'weight', width: 10 },
      { header: '货箱长度(CM)', key: 'long', width: 10 },
      { header: '货箱宽度(CM)', key: 'width', width: 10 },
      { header: '货箱高度(CM)', key: 'height', width: 10 },
      { header: '产品品牌', key: 'brand', width: 10 },
      { header: '产品材质', key: 'mercadoproductMaterial', width: 10 },
      { header: '件数', key: 'number', width: 10 },
    ];

    boxs.map((item: any, index: number) => {
      let tableRow = {
        name: item.name,
        mercadoskuNumber: item.mercadosku.number,
        mercadoproductName: item.mercadoproduct.name,
        mercadoproductEnName: item.mercadoproduct.enName,
        boxNumber: item.boxNumber,
        mercadoskuSalePrice: item.mercadosku.salePrice,
        weight: item.weight,
        long: item.long,
        width: item.width,
        height: item.height,
        brand: item.brand || '',
        mercadoproductMaterial: item.mercadoproduct.material,
        number: 1,
      };

      worksheet.addRow(tableRow);

      let imageId = workbook.addImage({
        filename: item.mercadosku.image.replace(
          `${process.env.BASE_REQUEST_URL}/`,
          'public/',
        ),
        extension: 'png',
      });

      worksheet.addImage(imageId, {
        tl: { col: 1, row: index + 1 }, // 图片起始位置，第 4 列（从 0 开始计数），当前行
        ext: { width: 100, height: 100 }, // 图片尺寸
      });
    });

    worksheet.addRow({
      number: outboundplan.totalBoxNumber,
      name: `QHSM${dayjs().format('YYYYMMDD')}${outboundplan.id}`,
    });

    // 定义保存修改后文件的路径，这里假设保存到项目根目录下的 output 文件夹中
    const outputPath = path.join(
      __dirname,
      `../../public`,
      `QHSM${dayjs().format('YYYYMMDD')}${outboundplan.id}.xlsx`,
    );
    // 将修改后的工作簿保存到指定路径
    await workbook.xlsx.writeFile(outputPath);

    return `${process.env.BASE_REQUEST_URL}/QHSM${dayjs().format('YYYYMMDD')}${outboundplan.id}.xlsx`;
  }

  async findAll(pageNum: number, pageSize: number) {
    const [list, count] = await Outboundplan.findAndCount({
      skip: (pageNum - 1) * pageSize,
      take: pageSize,
    });

    return { list, count };
  }

  async query(query: QueryOutboundplanDto) {
    let qeryBuilder = Outboundplan.createQueryBuilder('outboundplan');

    let { queryClone, pageNum, pageSize } = parseQueryParams(query, [
      //  'categoryId',
      'warehouseId',
    ]);

    qeryBuilder.where(queryClone);

    qeryBuilder.leftJoinAndSelect('outboundplan.warehouse', 'warehouse');
    qeryBuilder.leftJoinAndSelect('outboundplan.boxs', 'boxs');
    qeryBuilder.leftJoinAndSelect('boxs.mercadosku', 'boxsMercadosku');
    qeryBuilder.leftJoinAndSelect('boxs.mercadoproduct', 'boxsMercadoproduct');
    qeryBuilder.leftJoinAndSelect('boxs.warehouse', 'boxsWarehouse');

    // 关联查询
    if (query.warehouseId) {
      qeryBuilder.andWhere('warehouse.id = :warehouseId', {
        warehouseId: query.warehouseId,
      });
    }

    qeryBuilder.skip((pageNum - 1) * pageSize);
    qeryBuilder.take(pageSize);

    qeryBuilder.orderBy('outboundplan.createTime', 'DESC');

    let [list, count] = await qeryBuilder.getManyAndCount();

    return { list, count };
  }

  findOne(id: number) {
    return Outboundplan.findOneBy({ id });
  }

  async update(
    id: number,
    updateOutboundplanDto: UpdateOutboundplanDto,
    uid: number,
  ) {
    let warehouse = await Warehouse.findOne({
      where: { id: updateOutboundplanDto.warehouseId },
    });

    delete updateOutboundplanDto.warehouseId;
    let outboundplan = await Outboundplan.findOneBy({ id });

    if (outboundplan.status == 2) {
      throw new HttpException('该计划已运输，不允许修改', 403);
    }

    if (outboundplan.status == 3) {
      throw new HttpException('该计划已出库，不允许修改', 403);
    }

    if (outboundplan.status == 0) {
      throw new HttpException('该计划已作废，不允许修改', 403);
    }

    if (uid == 1 || uid == outboundplan.adminId) {
      // 计算库存数量
      let data = JSON.parse(outboundplan.data);
      let stock = 0;
      let totalBoxNumber = 0;

      data.map((item: any) => {
        item.boxNumberCountArray.map((item1: any) => {
          stock += Number(item1.boxNumber) * Number(item1.num);
          totalBoxNumber += Number(item1.num);
        });
      });

      outboundplan.totalNumber = stock;
      outboundplan.totalBoxNumber = totalBoxNumber;

      outboundplan.warehouse = warehouse;

      outboundplan.adminId = uid;

      outboundplan.data = updateOutboundplanDto.data;
      outboundplan.status = 1;

      await outboundplan.save();
    } else {
      throw new HttpException('没有权限', 403);
    }
  }

  remove(id: number) {
    return Outboundplan.update(id, { status: 0 });
  }

  async toShipping(id: number, mercadoBoxNumber: string, boxExpressNo: string) {
    let outboundplan = await Outboundplan.findOne({
      where: {
        id,
      },
      relations: {
        warehouse: true,
      },
    });

    let warehouse = outboundplan.warehouse;

    // 根据outboundplan计算生成box
    let data = JSON.parse(outboundplan.data);

    console.log('data', data);

    // 根据data 找到所有的box

    let boxArray = [];

    for await (const item of data) {
      for await (const boxNumberCount of item.boxNumberCountArray) {
        let queryRunner = Box.createQueryBuilder('box');

        queryRunner.leftJoinAndSelect('box.mercadosku', 'mercadosku');
        queryRunner.leftJoinAndSelect('box.mercadoproduct', 'mercadoproduct');

        queryRunner.where('box.outboundplanId = :outboundplanId', {
          outboundplanId: outboundplan.id,
        });

        queryRunner.where('box.warehouseId = :warehouseId', {
          warehouseId: warehouse.id,
        });

        queryRunner.andWhere('box.mercadoskuId = :mercadoskuId', {
          mercadoskuId: item.skuId,
        });

        queryRunner.andWhere('box.boxNumber = :boxNumber', {
          boxNumber: boxNumberCount.boxNumber,
        });

        // 创建计划时已把盒状态更新为2 现在只查询2的
        queryRunner.andWhere('box.status = :status', {
          status: 2,
        });

        queryRunner.skip(0);
        queryRunner.take(boxNumberCount.num);

        let boxs = await queryRunner.getMany();
        console.log(
          '%c [ boxs ]-505',
          'font-size:13px; background:pink; color:#bf2c9f;',
          boxs,
        );

        boxArray = [...boxArray, ...boxs];
      }
    }

    outboundplan.status = 2;

    if (mercadoBoxNumber) {
      outboundplan.mercadoBoxNumber = mercadoBoxNumber;
    } else if (boxExpressNo) {
      let boxExpressNoArray = JSON.parse(boxExpressNo);

      outboundplan.mercadoBoxNumber = Array.from(
        new Set(boxExpressNoArray.map((item) => item.mercadoBoxNumber)),
      ).join(',');
    }

    await outboundplan.save();

    let unpayArray = [];

    for await (const box of boxArray) {
      // 修改box的状态为已送出
      box.status = 3;
      box.outboundplan = outboundplan;
      if (mercadoBoxNumber) {
        box.mercadoBoxNumber = mercadoBoxNumber;
      } else if (boxExpressNo) {
        let boxExpressNoArray = JSON.parse(boxExpressNo);
        boxExpressNoArray.map((item: any) => {
          if (item.skuId == box.mercadosku.id) {
            item.boxNumberCountArray.map((boxNumberCount: any) => {
              if (boxNumberCount.boxNumber == box.boxNumber) {
                box.mercadoBoxNumber = item.mercadoBoxNumber;
              }
            });
          }
        });
      }

      await box.save();

      if (box.isPay == 0 || box.isPay == null) {
        unpayArray.push(box);
      }
    }

    // 更新SKU的库存数量
    return { boxArray, unpayArray };
  }

  async getProductAndSku(
    queryWarehouseProductSkuDto: QueryWarehouseProductSkuDto,
  ) {
    let queryRunner = Box.createQueryBuilder('box');

    queryRunner.leftJoinAndSelect('box.mercadosku', 'mercadosku');
    queryRunner.leftJoinAndSelect('box.mercadoproduct', 'mercadoproduct');

    queryRunner.where('box.warehouseId = :warehouseId', {
      warehouseId: queryWarehouseProductSkuDto.warehouseId,
    });

    // 只查询在海外仓的箱子，运输中的不查
    queryRunner.where('box.status = :status', {
      status: 1,
    });

    if (queryWarehouseProductSkuDto.mercadoproductId) {
      queryRunner.andWhere('box.mercadoproductId = :mercadoproductId', {
        mercadoproductId: queryWarehouseProductSkuDto.mercadoproductId,
      });
    }

    if (queryWarehouseProductSkuDto.mercadoskuId) {
      queryRunner.andWhere('box.mercadoskuId = :mercadoskuId', {
        mercadoskuId: queryWarehouseProductSkuDto.mercadoskuId,
      });
    }

    let list = await queryRunner.getMany();

    // 根据每个box装箱数，统计不同装箱数的数量
    let boxNumberList = list.map((item: any) => {
      return item.boxNumber;
    });

    // 对 boxNumberList 进行分组统计
    const boxNumberCountMap = new Map();

    boxNumberList.forEach((boxNumber) => {
      if (boxNumberCountMap.has(boxNumber)) {
        boxNumberCountMap.set(boxNumber, boxNumberCountMap.get(boxNumber) + 1);
      } else {
        boxNumberCountMap.set(boxNumber, 1);
      }
    });

    // 将 Map 转换为对象
    const boxNumberCount = Object.fromEntries(boxNumberCountMap);

    const boxNumberCountArray = Object.entries(boxNumberCount).map(
      ([boxNumber, count]) => ({
        boxNumber: Number(boxNumber),
        count,
      }),
    );

    return { list, boxNumberCountArray };
  }
}
